<?php declare(strict_types=1);

namespace Zyucv7\Core\Web\Session;

use Zyucv7\Core\Web\Exceptions\SessionException;
use Zyucv7\Core\Web\Session\Handler;

/**
 * 文件会话管理类
 */
class FileHandler extends Handler {
    
    private $savePath = '';
    private $sessionData = [];
    private $sessionId = '';
    private $lifetime = 604800; // 默认一周

    public function __construct(array $config) {

        $this->config = array_merge($this->config, $config);
        // 设置保存路径
        $this->savePath = $this->config['save_path'] ?: sys_get_temp_dir();
        
        if (!is_writable($this->savePath)) {
            throw SessionException::InvalidArgument("Session path '{$this->savePath}' is not writable.");
        }

        // 生成或获取会话ID
        if($this->config['session_key'] ?? '') {
            $this->sessionId = $this->config['session_key'];
        } else {
            $this->generateSessionId();
        }
    }

    // 生成新的会话ID
    private function generateSessionId(): void {
        $this->sessionId = ($this->config['file_prefix'] ?? 'sys_sess_') . bin2hex(random_bytes(16));
    }

    // 启动会话
    public function start() {
        $this->read();
        $this->isStarted = true;
    }

     /**
     * Calculate path to file.
     */
    private function getFilePath(): string
    {
        return $this->savePath.'/'.$this->sessionId.'.v7sess';
    }

    // 读取会话数据
    private function read(): void {
        if (file_exists($this->getFilePath())) {
            $data = file_get_contents($this->getFilePath());
            $this->sessionData = $data ? unserialize($data) : [];
        }
    }

    // 获取会话数据
    public function get(string $key, $default = null) {
        return $this->sessionData[$key] ?? $default;
    }

    // 写入会话数据
    public function write(): void {
        if (!$this->isStarted) {
            throw SessionException::Runtime("Session has not been started.");
        }
        $path = $this->getFilePath();
        $data = serialize($this->sessionData);
        if (file_put_contents($path, $data) === false) {
            throw SessionException::Runtime("Failed to write session data to '{$path}'.");
        }
    }

    // 设置会话数据
    public function set(string $key, $value): void
    {
        if(!isset($this->sessionData['expired_time'])) {
            // 初次创建会话，设置过期时间
            $this->sessionData['expired_time'] = time() + $this->lifetime;
        }
        $this->sessionData[$key] = $value;
        $this->write();
    }

    // 删除会话
    public function remove(string $key): void
    {
        if (isset($this->sessionData[$key])) {
            unset($this->sessionData[$key]);
        }
        $this->write();
    }

    // 清除会话
    public function clear(): void
    {
        $this->sessionData = [];
        if (file_exists($this->getFilePath())) {
            unlink($this->getFilePath());
        }
    }

    // 获取会话ID
    public function getId(): string
    {
        return $this->sessionId;
    }

    // 设置会话ID
    public function setId(string $id): void
    {
        $this->sessionId = $id;
    }

    // 获取所有的会话数据
    public function all(): array
    {
        return $this->sessionData;
    }

    // 判断是否过期
    public function isExpired(): bool
    {
        $expired_time = $this->sessionData['expired_time'] ?? 0;
        return time() > $expired_time;
    }
}